#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <cstring>
#include <unistd.h>

//模拟丐版的shell
//client端发送命令,server端接收命令
//server端接收命令后进行运行，将结果发送给client端，client端进行接收
int main(int argc,char* argv[])
{
    //程序启动
    if(argc!=2)
    {
        std::cerr<<"Usage: udpserver port"<<std::endl;
        return 1;
    }
    //创建socket网络文件
    int sock=socket(AF_INET,SOCK_DGRAM,0);//ipv4协议，套接字类型（传输udp/tcp）,套接字协议（0：默认协议）
    if(sock < 0)
    {
        std::cerr<<"socket"<<std::endl;
        return 2;
    }
    std::cout<<"sock:"<<sock<<std::endl;
    //创建套接字结构体-填入ip及port
    struct sockaddr_in local;
    memset(&local,0,sizeof(local));//初始化结构体
    local.sin_family=AF_INET;//通信协议 
    local.sin_port=htons(atoi(argv[1]));//网络端口传输时需要进行转换格式
    local.sin_addr.s_addr=htons(INADDR_ANY);//云服务器不建议绑定明确的ip，建议使用INADDR_ANY绑定该主机所有设备
    //将网络文件与套接字进行绑定（强相关）
    if(bind(sock,(struct sockaddr*)&local,sizeof(local))==-1)
    {
        std::cout<<"bind"<<std::endl;
        return 3;
    }
    //进行获取远端消息并回复
    while(1)
    {
        char message[128]={0};
        //接收远端的套接字信息-便于进行回复
        struct sockaddr_in peer; 
        socklen_t len=sizeof(peer);
        //接收命令
        ssize_t s=recvfrom(sock,message,sizeof(message)-1,0,(struct sockaddr*)&peer,&len); 
        if(s>0)
        {
            FILE* in=popen(message,"r");
            if(in==nullptr)
            {
                continue;
            }
            std::string ret;
            char line[128];
            while(fgets(line,sizeof(line)-1,in))
            {
                ret+=line;
            }
            sendto(sock,ret.c_str(),ret.size(),0,(struct sockaddr*)&peer,len);
            //  char* command[64]={0};
            // //进行解析命令
            // int i=1;
            // command[0]=strtok(message," ");
            // while(command[i]=strtok(message,nullptr))
            //     i++;
            // //创建子进程执行
            // if(fork()==0)
            // {
            //     //child
            //     //子进程继承了父进程的文件信息
            //     //将结果重定向到网络文件中，即子进程将结果重定向输出到客户端
            //     dup2(sock,1);
            //     execvp(command[0],command);
            //     std::cerr<<"execvp"<<std::endl;
            //     exit(4);//执行到这即为进程替换错误
            // }


        }
        
    }
    close(sock);
    return 0;
}
